package site.yunnong.atvris.portal.service.impl;

import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import site.yunnong.atvris.common.api.Page;
import site.yunnong.atvris.common.api.ResultCodeEnum;
import site.yunnong.atvris.common.dto.*;
import site.yunnong.atvris.common.enumeration.Constant;
import site.yunnong.atvris.common.enumeration.MediaStatusEnum;
import site.yunnong.atvris.common.enumeration.MediaTypeEnum;
import site.yunnong.atvris.common.enumeration.RankTypeEnum;
import site.yunnong.atvris.common.exception.YunnongBusinessException;
import site.yunnong.atvris.common.utils.RedisKeyUtils;
import site.yunnong.atvris.portal.util.SensitiveFilter;
import site.yunnong.atvris.common.utils.SqlUtils;
import site.yunnong.atvris.dao.domain.*;
import site.yunnong.atvris.dao.mapper.CommentsMapper;
import site.yunnong.atvris.dao.mapper.NewsMapper;
import site.yunnong.atvris.dao.mapper.VideoProfileMapper;
import site.yunnong.atvris.portal.service.CommentsService;
import site.yunnong.atvris.portal.service.NewsService;
import site.yunnong.atvris.portal.service.ReplyService;
import site.yunnong.atvris.service.InteractionService;
import site.yunnong.atvris.service.UserService;
import site.yunnong.atvris.service.VideoProfileService;
import site.yunnong.atvris.service.helper.OperatorHelper;
import site.yunnong.atvris.service.vo.CommentCardVO;
import site.yunnong.atvris.service.vo.ReplyVO;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 动态评论
 *
 * @author zhangjinghao
 * @email jhzhang9102@163.com
 * @date 2021-07-09 23:45:37
 */
@Service
public class CommentsServiceImpl implements CommentsService {

    @Resource
    private CommentsMapper commentsMapper;
    @Resource
    private UserService userService;
    @Resource
    private VideoProfileMapper videoProfileMapper;
    @Resource
    private VideoProfileService videoProfileService;
    @Resource
    private NewsService newsService;
    @Resource
    private ReplyService replyService;
    @Resource
    private NewsMapper newsMapper;
    @Resource
    private InteractionService interactionService;
    @Resource
    private RedisTemplate redisTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addComment(CommentsParam param) {
        if (StringUtils.isBlank(param.getContent())) {
            throw new YunnongBusinessException(ResultCodeEnum.ERROR_PARAM_ILLEGAL, "评论内容不可为空");
        }
        if (SensitiveFilter.containsSensitive(param.getContent())) {
            throw new YunnongBusinessException(ResultCodeEnum.ERROR_PARAM_ILLEGAL, "输入内容包含敏感词");
        }
        // 添加评论
        Comments comment = initComment(param);
        int count = commentsMapper.insertSelective(comment);
        if (MediaTypeEnum.VIDEO.getValue().equals(param.getMediaType())) {
            // 更新视频评论个数
            VideoProfile videoProfile = videoProfileService.queryByUvid(param.getMediaId());
            if (ObjectUtils.isEmpty(videoProfile)) {
                throw new YunnongBusinessException(ResultCodeEnum.ERROR_BUSINESS, "数据异常，添加评论失败");
            }
            videoProfile.setCommentCount(videoProfile.getCommentCount() + 1);
            videoProfileService.updateVideoProfile(videoProfile);
            // 计算视频分数
            String mediaScoreKey = RedisKeyUtils.getMediaScoreKey(MediaTypeEnum.VIDEO.getValue());
            redisTemplate.opsForSet().add(mediaScoreKey, param.getMediaId());
        } else if (MediaTypeEnum.NEWS.getValue().equals(param.getMediaType())) {
            // 在动态上评论,更新动态评论个数
            News news = newsService.queryByUnid(param.getMediaId());
            if (ObjectUtils.isEmpty(news)) {
                throw new YunnongBusinessException(ResultCodeEnum.ERROR_BUSINESS, "数据异常，添加动态评论失败");
            }
            news.setCommentCount(news.getCommentCount() + 1);
            newsMapper.updateByPrimaryKeySelective(news);
        }

        // todo 触发发表评论事件，消息推送
        return count;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int delComment(CommentDeleteParam param) {
        // 删除评论
        int count = deleteMediaComment(param);
        // 删除回复
        ReplyDeleteParam replyDeleteParam = ReplyDeleteParam.builder().mediaId(param.getMediaId())
                .mediaType(param.getMediaType())
                .cid(param.getId())
                .build();
        replyService.removeMediaReply(replyDeleteParam);
        // 计算评论量
        if (MediaTypeEnum.VIDEO.getValue().equals(param.getMediaType())) {
            VideoProfile videoProfile = videoProfileService.queryByUvid(param.getMediaId());
            if (videoProfile == null) {
                // 没查到，无需更新其评论量
                return count;
            }
            videoProfile.setCommentCount(videoProfile.getCommentCount() - count);
            videoProfileService.updateVideoProfile(videoProfile);
            // 计算视频分数
            String mediaScoreKey = RedisKeyUtils.getMediaScoreKey(MediaTypeEnum.VIDEO.getValue());
            redisTemplate.opsForSet().add(mediaScoreKey, param.getMediaId());
        } else if (MediaTypeEnum.NEWS.getValue().equals(param.getMediaType())) {
            News news = newsService.queryByUnid(param.getMediaId());
            if (news == null) {
                // 没查到，无需更新其评论量
                return count;
            }
            news.setCommentCount(news.getCommentCount() - count);
            newsService.updateNews(news);
        }
        
        return count;
    }

    private int deleteMediaComment(CommentDeleteParam param)  {
        CommentsExample example = new CommentsExample();
        CommentsExample.Criteria criteria = example.createCriteria();
        if (param.getId() != null) {
            criteria.andIdEqualTo(param.getId());
        } else {
            criteria.andMediaIdEqualTo(param.getMediaId())
                    .andMediaTypeEqualTo(param.getMediaType());
        }
        return commentsMapper.deleteByExample(example);
    }

    private int deleteByIds(List<Long> ids) {
        CommentsExample example = new CommentsExample();
        example.createCriteria().andIdIn(ids);
        return commentsMapper.deleteByExample(example);
    }

    @Override
    public Page<CommentCardVO> listWithReply(CommentQueryParam param) {
        com.github.pagehelper.Page<Comments> commentsPage =  queryPage(param);
        Long uuid = OperatorHelper.isLogin() ? OperatorHelper.getLoginUuid() : null;
        List<CommentCardVO> results = Optional.of(commentsPage.getResult())
                .orElse(Lists.newArrayList())
                .stream().map(comments -> buildCommentVO(uuid, comments)).collect(Collectors.toList());
        return new Page<>(commentsPage.getPageNum(), commentsPage.getPageSize(), commentsPage.getTotal(), results);
    }

    private com.github.pagehelper.Page<Comments> queryPage(CommentQueryParam param) {
        CommentsExample example = new CommentsExample();
        example.createCriteria()
                .andMediaIdEqualTo(param.getMediaId())
                .andMediaTypeEqualTo(param.getMediaType())
                // 有效数据
                .andStatusNotEqualTo(MediaStatusEnum.NOT_PASSED.getValue());
        String sortBy = RankTypeEnum.getFieldByValue(param.getSortType());
        example.setOrderByClause(SqlUtils.generateOrderByClause(sortBy, param.getSortRule()));
        return PageHelper.startPage(param.getPageNum(), param.getPageSize()).doSelectPage(() -> {
            commentsMapper.selectByExample(example);
        });
    }

    @Override
    public int updateByExampleSelective(Comments newComment, CommentsExample commentsExample) {
        return commentsMapper.updateByExampleSelective(newComment, commentsExample);
    }

    private CommentCardVO buildCommentVO(Long uuid, Comments comments) {
        CommentCardVO vo = new CommentCardVO();
        BeanUtils.copyProperties(comments, vo);
        // 评论点赞量
        int likedCount = interactionService.findMediaLikedCount(MediaTypeEnum.COMMENT.getValue(), comments.getId());
        vo.setLikedCount(likedCount);
        // 是否已点赞过该评论
        if (uuid == null) {
            vo.setHasSupport(false);
        } else {
            boolean hasSupport = interactionService.findMediaLikeStatus(uuid, MediaTypeEnum.COMMENT.getValue(), comments.getId());
            vo.setHasSupport(hasSupport);
        }
        // 三条评论记录
        ReplyQueryParam param = ReplyQueryParam.builder()
                .cid(comments.getId())
                .pageNum(1)
                .pageSize(3)
                .build();
        Page<ReplyVO> replyVoPage = replyService.queryPage(param);
        vo.setReplyVoPage(replyVoPage);
        return vo;
    }

    private Comments initComment(CommentsParam param) {
        Comments comment = new Comments();
        param.setContent(param.getContent());
        BeanUtils.copyProperties(param, comment);
        User user = OperatorHelper.getCurrentUser();
        comment.setUuid(user.getUuid());
        comment.setUserAvatar(user.getAvatar());
        comment.setUserNickname(user.getNickname());
        comment.setStatus(MediaStatusEnum.ISSUE_REVIEW.getValue());
        comment.setType(Constant.ORDINARY_COMMENT);
        comment.setCreateTime(LocalDateTime.now());
        comment.setUpdateTime(LocalDateTime.now());
        return comment;
    }
}

